
class Object
  
  @@unprocessed ||= []
  @@__once_helper ||= {}

  def visit &block
    block.call(self)
  end

  def self.once &block
    if block_given?
      unless @@__once_helper[self]
        @@__once_helper[self] = true
        @@unprocessed << block
      end
    else
      r = @@unprocessed
      @@unprocessed = []
      r
    end
  end


  def tap &block
    block.call self
    self
  end

  #who is talking?
  def p *a
    puts caller.first + 'says: '
    Kernel.p *a
  end

  def print
    puts self.to_s
    self
  end

  def printi *a
    p self
    self
  end
end



def puts *a
  StandardOutput.instance.puts a
  Kernel.puts *a
end

def p *a
  a.map { |argument| 
      StandardOutput.instance.p argument
    }
  Kernel.p *a
end

class StandardOutput < MySingleton
  def initialize_singleton
    s = new
    Event.on('get_stdout') { |e|
      s.on_list e
    }
    s
  end

  def initialize
    @putslog ||= []
  end

  def on_list e
    e.respond(
      "client:get_stdout_response",
      :log => list().
        map { |log|
          {
            :time => log[0],
            :line => log[1]
          }
        }
      )
  end

  def p *a
    log [:p, a.map { |b| DevConsole.new.hilite(b)}]
  end

  def puts *a
    log [:puts, a]
  end

  def log item
    @putslog << [timestamp, item]
    while @putslog.length > 100
      @putslog.shift
    end
  end

  def timestamp
    Time.now.to_i
  end

  def list from = nil
    @putslog.select { |record|
      record[0] >= from
    }.map { |record|
      record[1]
    }
  end

  class StandardOutputMock < StandardOutput
    attr_accessor :timestamp
  end

  class Test < AppTest
    def test_puts_puts_argumens_into_list
      s = StandardOutput.new
      s.puts "abc"
      eq s.list[0][1], "abc"
    end

    def test_on_list_responds_with_client_event_with_list_in_json
      s = StandardOutputMock.new
      s.timestamp = 123
      s.puts "abc"
      e = Event.new nil, :params => {}
      s.on_list e

      r = e.response[0]
      eq r.name, "client:get_stdout_response"
      eq r.log[0][:line], "abc"
      eq r.log[0][:time], 123
    end
  end
end



class Symbol
  def to_proc
    proc { |obj, *args| obj.send(self, *args) }
  end
end

class Hash
  def stringify_keys
    inject({}) do |options, (key, value)|
      options[key.to_s] = value
      options
    end
  end

  def stringify_keys!
    keys.each do |key|
      self[key.to_s] = delete(key)
    end
    self
  end
end


class Array
  def tail
    a = dup
    a.shift
    a
  end

  def init
    a = dup
    a.pop
    a
  end

  class Test < FwTest
    def test_tail_returns_array_without_its_first_item
      eq [1,2,3].tail, [2,3]
    end

    def test_tail_does_not_change_the_original_array
      a = [1,2,3]
      a.tail
      eq a, [1,2,3]
    end

    def test_init_returns_array_without_its_last_item
      eq [1,2,3].init, [1,2]
    end

    def test_init_does_not_change_the_original_array
      a = [1,2,3]
      a.init
      eq a, [1,2,3]
    end
  end
end
